// Read ellipsometer values via LabJack
//use easyU3 code from labjack as basis

// use channel 0 as input for photodiode.
// use channel 4 as control flag input
// use channel 5 as position flag input
// 30/4/2010
// this version attempts to completely replicate logic of ellipsometer

// some of the levels are the wrong way round
#include "AutoE.h"

int millisleep(int time)
// function to allow delays of less that one second
{
	int millisecs, microsecs;
	struct timeval tv;
	
	millisecs=time;
	microsecs=millisecs*1000;
	
	tv.tv_sec=microsecs/1000000;
	tv.tv_usec=microsecs%1000000;
	
	select(0, NULL, NULL, NULL, &tv);
	return(0);
}

int WaitForRef(HANDLE hDevice,u3CalibrationInfo caliInfo)
// Function to wait for reference pulse 
{
	long Reference, error,DAC1Enable_Ref;
	int LoopCheck;
	double value;
	Reference=1;
	LoopCheck=1;
	while(Reference)
		// Reference is usually at a high value. wait for reference to go to a low state - this signifies the start 
		// of the cycle.
		// would use digital i/o, but there seems to be a problem picking up the switch (need signal conditioning?)
	{		
		// read in digital value from digital input
		if ((error=eAIN( hDevice,&caliInfo,LoopCheck,&DAC1Enable_Ref,4,31,&value,0,0,0,0,0,0))!=0) 
		{
			printf("LoopCheck=%3d\n",LoopCheck);
			return 1;
		}
		
		if (value<1.5) return 0; // have found an edge
		
		LoopCheck=0;
	}
	return (1);	
}

int dWaitForRef(HANDLE hDevice,u3CalibrationInfo caliInfo)
// Function to wait for digital reference pulse 
{
	long Reference, error,ConfigIO;
	int LoopCheck;
	Reference=1;
	LoopCheck=1;
	ConfigIO=1;
	while(Reference)
		// Reference is usually at a high value. wait for reference to go to a low state - this signifies the start 
		// of the cycle.
		
	{		
		// read in digital value from digital input
		if ((error=eDI( hDevice,
					   ConfigIO,
					   06,
					   &Reference))!=0) 
		{
			return 1;
		}
		
		if (Reference<1) return 0; // have found an edge
		
		ConfigIO=0;
	}
	return (1);	
}


int WaitForCount(HANDLE hDevice,u3CalibrationInfo caliInfo)
// Function to wait for count pulse 
{
	long Reference, error,DAC1Enable_Count;
	int LoopCheck;
	double value;
	Reference=1;
	LoopCheck=1;
	while(Reference)
		// count is usually at a high value. wait for count to go to a low state - this signifies the start 
		// of the cycle.
		// would use digital i/o, but there seems to be a problem picking up the switch (need signal conditioning?)
	{		
		// read in digital value from digital input
		if ((error=eAIN( hDevice,&caliInfo,LoopCheck,&DAC1Enable_Count,5,31,&value,0,0,0,0,0,0))!=0) return 1;
		if (value<1.5) return 0; // have found an edge
		
	}
	return (1);	
}

int dWaitForCount(HANDLE hDevice,u3CalibrationInfo caliInfo)
// Function to wait for count pulse (use channel 17)
{
	long  error,Count,ConfigIO;
	int LoopCheck;
	Count=1;
	LoopCheck=1;
	ConfigIO=1; // keeps track of whether the channel has been set to  in or out 
	while(Count)
		// count is usually at a high value. wait for count to go to a low state - this signifies the start 
		// of the cycle.
		
	{		
		// read in digital value from digital input
		if ((error=eDI( hDevice,
					   ConfigIO,
					   05,
					   &Count))!=0) 
		{
			return 1;
		}
		
		if (Count<1) return 0; // have found an edge
		
		ConfigIO=0; 
	}
	return (1);	
}

int CompensatorIn(HANDLE hDevice,u3CalibrationInfo caliInfo)
// routine to move compenstor into laser beam path
// CTL0 on ellipsometer - connect to channel 16 on U3 box

{
	long ConfigIO, CTL0,error;
	ConfigIO=1;
	CTL0=04;
	if ((error=eDO( hDevice, ConfigIO,CTL0,0)!=0))
	{
		return 1;
	}
	ConfigIO=0;// channel is now set to  digital output
	return 0;
}

int CompensatorOut(HANDLE hDevice,u3CalibrationInfo caliInfo)
// routine to move compenstor into laser beam path
// CTL0 on ellipsometer - connect to channel 4 on U3 box

{
	long ConfigIO, CTL0,error;
	ConfigIO=1;
	CTL0=04;
	if ((error=eDO( hDevice, ConfigIO,CTL0,1)!=0))
	{
		return 1;
	}
	ConfigIO=0;// channel is now set to  digital output
	return 0;
}

int CollectValues(WINDOW *mainwnd, HANDLE hDevice, u3CalibrationInfo caliInfo, int nValues, double* VArray)
// function to aquire nValues voltages from the ellipsometer and store them in the array VArray
{
	long LoopCheck;
	int values;
	int error;
	long DAC1Enable;
	double value;
	values=0;
	DAC1Enable=1;
	LoopCheck=1;
	
	while(values<nValues) // use  360 degrees (5 degree intervals - this is set by the ellipsometer hardware)
	{
		//		Count=1;
		
		// wait for a count pulse  
		
		if (dWaitForCount(hDevice, caliInfo))
		{
			printw("Count fail\n");
			refresh();
			return 1;
		}
		// Now get photodiode value	
		if ((error=eAIN( hDevice,&caliInfo,LoopCheck,&DAC1Enable,0,31,&value,0,0,0,0,0,0))!=0) 
		{
			wprintw(mainwnd,"Analogue read error");
			refresh();
			millisleep(2000);
			return 1;
		}
		// function call has worked so set LoopCheck to zero for future calls
		LoopCheck=0;
		VArray[values]=value;
		//printf("AIN0 value = %.3f\n	", Voltage[values]);
		values++;
	}
	
	
	
	
	return 0;
}

int VoltageToPsiDelta(double* Voltage,int size, double angle, double* psi, double* delta)
// calculate the 
{
	return 0;
}

int AutoE(WINDOW *mainwnd)
{
    HANDLE hDevice;
    u3CalibrationInfo caliInfo;
    int localID;
    long Reference,Count, error;
	long ConfigIO,PCTL;
    int MainLoop;
    int LoopCheck;
    double* Voltage;
	
	// variables for Psi, Delta calculation
	double k0,k1,k2;
	double angle;
	char texta[20];// user input angle
	// psi and delta values - subscripts according to whether compensator is used or not
	double psi_out,delta_out;
	double psi_in,delta_in;
	double psi,delta;
	
	//memory allocation
	Voltage=(double *)malloc(72*sizeof(double));
	if (Voltage==NULL)
	{
		wprintw(mainwnd,"Error allocating array memory\n");
		refresh();
		millisleep(2000);
		
		goto done;
	}
	
	// memory allocated OK.
	clear();
	
    //Open first found U3 over USB
    localID = -1;
    if( (hDevice = openUSBConnection(localID)) == NULL)
	{
		wprintw(mainwnd,"Error! No device found - plug the LabJack in!");
		refresh();
		
        goto done;
	}
    //Get calibration information from UE9
    if((getCalibrationInfo(hDevice, &caliInfo)) < 0)
        goto close;
	// prompt user for angle - need to extend this functionality
	echo();
	wprintw(mainwnd,"\n\nAngle?");
	refresh();
	getstr(texta);
	
	angle=M_PI*atof( texta)/180.;
	
	wprintw(mainwnd,"Testing operation of compensator\n");
	refresh();
	
	// move compensator out of beam
	wprintw(mainwnd,"moving compensator out of beam\n");
	refresh();
	if((error=CompensatorOut( hDevice, caliInfo))!=0)
	{
		wprintw(mainwnd,"Error with compensator\n");
		refresh();
		millisleep(5000);
		goto done;
	}
	millisleep(2000);
	wprintw(mainwnd,"moving compensator into beam\n");
	refresh();
	// move compensator into beam
	if((error=CompensatorIn( hDevice, caliInfo))!=0)
	{
		wprintw(mainwnd,"Error with compensator\n");
		refresh();
		millisleep(5000);
		goto done;
	}
	millisleep(2000);	
	wprintw(mainwnd,"moving compensator out of beam\n");	
	refresh();
	// move compensator out of beam
	if((error=CompensatorOut( hDevice, caliInfo))!=0)
	{
		wprintw(mainwnd,"Error with compensator\n");
		refresh();
		millisleep(2000);
		goto done;
	}
	
	// set pctl to high - channel 07 for PCTL
	ConfigIO=1;
	PCTL=07;
	if ((error=eDO( hDevice, ConfigIO,PCTL,1)!=0)) // logical 0 tells ellipsometer that computer is not ready to accept data - this is a hang over from the old system.
	{
		printw("Error setting PCTL flag!");
		refresh();
		
		goto close;
	}
	ConfigIO=0;// channel is now set to  digital output
	
	
	
	// use a loop to cycle until control flag is set
	MainLoop=0;
	LoopCheck=1;// keeps track of whether a channel has been set to the correct type
	Reference=1;
	Count=1;
	//Voltage=0.;//default value
	
	while(!MainLoop)
	{	
		//step one set PCTL to low
		eDO( hDevice, ConfigIO,PCTL,0); // logical low
		// this triggers the beginning of the process
		// if PCTL is in ready state and a reference pulse is recieved thent the sequence gets underway.
		
		if ((error=dWaitForRef(hDevice, caliInfo))!=0) // this function returns zero once an edge is found on the reference
		{
			wprintw(mainwnd,"Reference fail\n");
			refresh();
			goto close;
		}
		
		
		// To have got here then the reference signal must have gone low
		// can begin to read in values  
		if((error=CollectValues(mainwnd, hDevice, caliInfo, 72, Voltage))!=0)
		{
			wprintw(mainwnd,"Error with voltage collection\n");
			refresh();
			millisleep(2000);
			goto close;
		}
		
		// set PCTL to high
		eDO( hDevice, ConfigIO,PCTL,1);
		
		// Now have the data, need to convert to Psi and Delta
		// angle=70; // default value
		k0=0.;
		k1=0.;
		k2=0.;
		
		
		// k0= is the average value of the readings.
		int i;
		for (i=0;i<72;i++) k0+=Voltage[i];
		k0/=72.;
		
		// printf("k0=%.4f\n",k0);
		double rangle;
		
		rangle=5.0*M_PI/180.; // basic angle in radians
		// k1 =2*sum(Vi*cos(2*anglei))/N
		// k1 =2*sum(Vi*sin(2*anglei))/N
		
		for (i=0;i<72;i++) k1+=(Voltage[i]*cos(2.0*rangle*i));
		for (i=0;i<72;i++) k2+=(Voltage[i]*sin(2.0*rangle*i)); 
		
		k1*=(2.0/72.);
		k2*=(2.0/72.0);
		
		wprintw(mainwnd,"k0=%2.3f k1=%2.3f k2=%2.3f \n",k0,k1,k2);
		refresh();
		psi_out=atan(sqrt((k0+k1)/(k0-k1)));
		delta_out=acos(k2/sqrt((k0*k0-k1*k1)));
		
		// move compensator into beam
		if((error=CompensatorIn( hDevice, caliInfo))!=0)
		{
			wprintw(mainwnd,"Error with compensator\n");
			refresh();
			millisleep(2000);
			goto done;
		}
		
		// acquire voltages
		//step one set PCTL to low
		eDO( hDevice, ConfigIO,PCTL,0);
		// this triggers the beginning of the process
		
		if ((error=dWaitForRef(hDevice, caliInfo))!=0) // this function returns zero once an edge is found on the reference
		{
			wprintw(mainwnd,"Reference fail\n");
			refresh();
			goto close;
		}
		
		
		// To have got here then the reference signal must have gone low
		// can begin to read in values  
		if((error=CollectValues(mainwnd, hDevice, caliInfo, 72, Voltage))!=0)
		{
			wprintw(mainwnd,"Error with voltage collection\n");
			refresh();
			millisleep(2000);
			goto close;
		}
		
		// set PCTL to high
		eDO( hDevice, ConfigIO,PCTL,1);
		
		// Now have the data, need to convert to Psi and Delta
		// angle=70; // default value
		k0=0.;
		k1=0.;
		k2=0.;
		
		
		// k0= is the average value of the readings.
		
		for (i=0;i<72;i++) k0+=Voltage[i];
		k0/=72.;
		
		// printf("k0=%.4f\n",k0);
		
		
		rangle=5.0*M_PI/180.; // basic angle in radians
		// k1 =2*sum(Vi*cos(2*anglei))/N
		// k1 =2*sum(Vi*sin(2*anglei))/N
		
		for (i=0;i<72;i++) k1+=(Voltage[i]*cos(2.0*rangle*i));
		for (i=0;i<72;i++) k2+=(Voltage[i]*sin(2.0*rangle*i)); 
		
		k1*=(2.0/72.);
		k2*=(2.0/72.0);
		
		wprintw(mainwnd,"k0=%2.3f k1=%2.3f k2=%2.3f \n",k0,k1,k2);
		refresh();
		psi_in=atan(sqrt((k0+k1)/(k0-k1)));
		delta_in=acos(k2/sqrt((k0*k0-k1*k1)));	
		
		// choose data set
		if ((delta_out<(45.*M_PI/180.))||(delta_out>(135.*M_PI/180.)))
		{
			delta=delta_in;
		}else
		{
			delta=delta_out;
		}
		psi=psi_out; // arbitary choice
		
		wprintw(mainwnd,"Psi=%1.3f  Delta=%1.3f\n",180.*psi/M_PI,180.*delta/M_PI);
		refresh();
		millisleep(1000);
		// solve for n, d
		solvepsidelta(mainwnd, angle,  delta,  psi);
		
		
		
		
		MainLoop++;
	}
	
close:
    if(error > 0)
		wprintw(mainwnd,"Received an error code of %ld\n", error);
    closeUSBConnection(hDevice);
done:	
	millisleep(2000);
	return 0;
}


